<?php

namespace Twilio\Jwt;


use Twilio\Jwt\Grants\Grant;

class AccessToken {
	private $signingKeySid;
	private $accountSid;
	private $secret;
	private $ttl;
	private $identity;
	private $nbf;
	/** @var Grant[] $grants */
	private $grants;
	/** @var string[] $customClaims */
	private $customClaims;

	public function __construct( $accountSid, $signingKeySid, $secret, $ttl = 3600, $identity = null ) {
		$this->signingKeySid = $signingKeySid;
		$this->accountSid    = $accountSid;
		$this->secret        = $secret;
		$this->ttl           = $ttl;

		if ( ! is_null( $identity ) ) {
			$this->identity = $identity;
		}

		$this->grants       = array();
		$this->customClaims = array();
	}

	/**
	 * Returns the identity of the grant
	 *
	 * @return string the identity
	 */
	public function getIdentity() {
		return $this->identity;
	}

	/**
	 * Set the identity of this access token
	 *
	 * @param string $identity identity of the grant
	 *
	 * @return $this updated access token
	 */
	public function setIdentity( $identity ) {
		$this->identity = $identity;

		return $this;
	}

	/**
	 * Returns the nbf of the grant
	 *
	 * @return integer the nbf in epoch seconds
	 */
	public function getNbf() {
		return $this->nbf;
	}

	/**
	 * Set the nbf of this access token
	 *
	 * @param integer $nbf nbf in epoch seconds of the grant
	 *
	 * @return $this updated access token
	 */
	public function setNbf( $nbf ) {
		$this->nbf = $nbf;

		return $this;
	}

	/**
	 * Add a grant to the access token
	 *
	 * @param Grant $grant to be added
	 *
	 * @return $this the updated access token
	 */
	public function addGrant( Grant $grant ) {
		$this->grants[] = $grant;

		return $this;
	}

	/**
	 * Allows to set custom claims, which then will be encoded into JWT payload.
	 *
	 * @param string $name
	 * @param string $value
	 */
	public function addClaim( $name, $value ) {
		$this->customClaims[ $name ] = $value;
	}

	public function __toString() {
		return $this->toJWT();
	}

	public function toJWT( $algorithm = 'HS256' ) {
		$header = array(
			'cty' => 'twilio-fpa;v=1',
			'typ' => 'JWT'
		);

		$now = time();

		$grants = array();
		if ( $this->identity ) {
			$grants['identity'] = $this->identity;
		}

		foreach ( $this->grants as $grant ) {
			$payload = $grant->getPayload();
			if ( empty( $payload ) ) {
				$payload = json_decode( '{}' );
			}

			$grants[ $grant->getGrantKey() ] = $payload;
		}

		if ( empty( $grants ) ) {
			$grants = json_decode( '{}' );
		}

		$payload = array_merge( $this->customClaims, array(
			'jti'    => $this->signingKeySid . '-' . $now,
			'iss'    => $this->signingKeySid,
			'sub'    => $this->accountSid,
			'exp'    => $now + $this->ttl,
			'grants' => $grants
		) );

		if ( ! is_null( $this->nbf ) ) {
			$payload['nbf'] = $this->nbf;
		}

		return JWT::encode( $payload, $this->secret, $algorithm, $header );
	}
}
